package com.starblink.android.basic.sensorsdata.spm.impl

import android.os.Build
import android.util.Log
import com.benasher44.uuid.uuid4
import com.blankj.utilcode.util.AppUtils
import com.blankj.utilcode.util.ProcessUtils
import com.starblink.android.basic.BuildConfig
import com.starblink.android.basic.appsflyer.AppsflyerManager
import com.starblink.android.basic.bridge.BridgeCommand
import com.starblink.android.basic.bridge.BridgeUtil
import com.starblink.android.basic.ext.toBean
import com.starblink.android.basic.ext.toJson
import com.starblink.android.basic.network.base.BaseApiClient
import com.starblink.android.basic.network.base.BaseApiConfig
import com.starblink.android.basic.network.base.BaseSiteSwitch
import com.starblink.android.basic.network.base.SkGqlClient
import com.starblink.android.basic.network.config.HeadsHandle
import com.starblink.android.basic.sensorsdata.room.entity.SKTraceEntity
import com.starblink.android.basic.sensorsdata.room.entity.SkAntEntity
import com.starblink.android.basic.sensorsdata.room.mana.SkTraceDatabaseManager
import com.starblink.android.basic.sensorsdata.spm.GTrackerAssistUtils
import com.starblink.android.basic.sensorsdata.spm.cfg.SpmDefaultConfig
import com.starblink.android.basic.sensorsdata.spm.event.TrackEvent
import com.starblink.android.basic.user.UserDataCenter
import com.starblink.basic.storage.SkStorage
import com.starblink.basic.util.CommUtils
import com.starblink.basic.util.NetWorkUtil
import com.starblink.basic.util.log.YYLogUtils
import com.starblink.rocketreserver.BuriedPointReportMutation
import com.starblink.rocketreserver.fragment.*
import kotlinx.coroutines.*
import okhttp3.Headers.Companion.toHeaders
import okhttp3.MediaType.Companion.toMediaType
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.RequestBody.Companion.toRequestBody
import okhttp3.logging.HttpLoggingInterceptor
import java.util.*
import java.util.concurrent.TimeUnit


/**
 * 埋点组装数据 并上报
 */
object SpmTrackHandler {
    private val deviceId = UserDataCenter.getDeviceId(CommUtils.getContext())
    private val clientVersion = AppUtils.getAppVersionName()
    private val tz = TimeZone.getDefault().getDisplayName(false, TimeZone.SHORT)
    private val mModel = Build.MODEL
    private val brand = Build.BRAND
    private val language = Locale.getDefault().language
    private val networkType = NetWorkUtil.getNetworkType(CommUtils.getContext()).name
    private val osVersion = Build.VERSION.RELEASE
    private val sessionId = uuid4().toString()
    private val reportList =
        listOf("40005", "50003", "20001", "20022", "20028", "30145", "30140", "33057")
    private val ignorePageList = listOf("10179", "10108", "10163", "10164")

    //        "${System.currentTimeMillis()}${Random().nextInt(10)}${Random().nextInt(10)}"
    private const val buildType = BuildConfig.BUILD_TYPE
    private val buildNumber = AppUtils.getAppVersionCode().toString()

    //false 不用切
    // ture 需要切站点
    var siteStatusHasSwitch = false

    private val spmClient = OkHttpClient.Builder()
        .callTimeout(30, TimeUnit.SECONDS)
        .connectTimeout(30, TimeUnit.SECONDS)
        .readTimeout(30, TimeUnit.SECONDS)
        .writeTimeout(30, TimeUnit.SECONDS)
        .retryOnConnectionFailure(true)
        .followRedirects(false)
        .addInterceptor(HttpLoggingInterceptor().apply {
            setLevel(if (BuildConfig.DEBUG) HttpLoggingInterceptor.Level.BODY else HttpLoggingInterceptor.Level.NONE)
        })
        .build()


    /**
     *
     */
    @OptIn(DelicateCoroutinesApi::class)
    fun addSingleTrackData(inputEntity: SkAntEntity) {
        GlobalScope.launch {
            GTrackerAssistUtils.removeDuplication(inputEntity) {
                //从队列抓一个出来 不然spmPrev会不准
                val antEntity = GTrackerAssistUtils.peekQueue()
                var entity = getBaseSKTraceEntity()
                entity.trackUniqueId = antEntity.trackUniqueId
                entity.ts = System.currentTimeMillis()
                entity.userId = UserDataCenter.getAccountInfo()?.id
                entity.event = antEntity.event
                entity.country =
                    UserDataCenter.getLocalCountryCode() // UserDataCenter.getLocalCountry() // 奋强让使用country code
                entity.eventParams = antEntity.eventParams
                entity.eventPath = listOf()
                entity.spmCnt = antEntity.spmCnt
                entity.trackEvent = antEntity.event
//                entity.trackEvent = GTrackerAssistUtils.fetchEventId(
//                    antEntity.spmCnt
//                )
                entity.spmPrev = GTrackerAssistUtils.previousEvent//antEntity.spmPrev ?:
                entity.traceInfo = antEntity.traceInfo
                entity.params = antEntity.params
//                GTrackerAssistUtils.addQueue(entity)
                entity.siteType = BaseSiteSwitch.currentSite?.type

                if (entity.event == "2") {
                    YYLogUtils.e("spm---> 开始上报 --->类型 曝光 ID --->traceInfo ${antEntity.traceInfo}   ${entity.trackEvent} ${entity.trackUniqueId} ${entity.spmCnt}  ${entity.spmPrev} ${antEntity.businessID} \n${antEntity.params}")
                } else {
                    YYLogUtils.e("spm---> 开始上报 --->类型 ${entity.event} ID --->traceInfo ${antEntity.traceInfo} ${entity.trackEvent} ${entity.trackUniqueId} ${entity.spmCnt} \n${antEntity.params}")
                }

                YYLogUtils.e("spm---> 进程 ${ProcessUtils.getCurrentProcessName()} ---> ${entity.spmPrev} ${entity.spmCnt}")


                //记录这个点
                GTrackerAssistUtils.previousEvent = antEntity.spmCnt
                //跨进程切换Web进程站点
                BridgeUtil.sendCommonData(
                    BridgeCommand.Common.previousEvent,
                    GTrackerAssistUtils.previousEvent
                )

                AppsflyerManager.reportTrack(entity)

                async {
                    if (siteStatusHasSwitch) {
                        async {
                            SkTraceDatabaseManager.db.skTraceDao.save(entity)
                        }
                    } else {
                        upload(entity, uploadSuccess = {
                            if (!UserDataCenter.successUploadOtherSpm) {
                                UserDataCenter.successUploadOtherSpm = true
                            }
                            YYLogUtils.e("spm---> 埋点上报成功 --->类型 ${entity.event} ${entity.spmCnt}  ID ---> ${entity.trackEvent} ${entity.trackUniqueId}")
//                        GTrackerAssistUtils.removeQueue(entity)
                        }, uploadFail = {
                            //失败了往数据库插
                            async {
                                SkTraceDatabaseManager.db.skTraceDao.save(entity)
                            }
                        })
                    }
                }

                if ((antEntity.event == TrackEvent.elementClick.value || antEntity.event == TrackEvent.statistics.value
                            || antEntity.event == TrackEvent.appLifeCycle.value) && reportList.contains(
                        GTrackerAssistUtils.fetchEventId(
                            antEntity.spmCnt
                        )
                    ) && !ignorePageList.contains(
                        GTrackerAssistUtils.getPageId(
                            antEntity.spmCnt
                        )
                    )
                ) {//上报点位有：40005、50003、20001、20022
                    //页面是 10179、10108、10163、10164、不上报 会跳转到商品详情
                    reportPoint(entity.toJson())
                }
            }
        }
    }

    /**
     * 上报特殊埋点
     */
    private fun reportPoint(jsonString: String?) {
        if (!jsonString.isNullOrEmpty()) {
            CoroutineScope(Dispatchers.IO).launch {
                val response = SkGqlClient.skMutation(
                    BuriedPointReportMutation(
                        jsonString
                    ),
                )
                if (response != null) {
                    Log.d("ProductLinkIntercept", "process:  ${response.data}")
                }
            }
        }
    }

    /**
     * https://blog.csdn.net/weixin_63357306/article/details/128918616
     */
    suspend fun upload(
        entry: SKTraceEntity,
        uploadSuccess: () -> Unit,
        uploadFail: () -> Unit
    ) {

        try {
            withContext(Dispatchers.IO) {
                val requestBody = entry.toJson().toRequestBody("application/json".toMediaType())
                val request = Request.Builder()
                    .url(tarSiteUrl(entry))
                    .headers(HeadsHandle.headers.toHeaders())
                    .post(requestBody)
                    .build()
                val call = spmClient.newCall(request)
                val response = call.execute()
                if (response.isSuccessful) {
                    uploadSuccess.invoke()
                } else {
                    uploadFail.invoke()
                }
            }
        } catch (e: Exception) {
            uploadFail.invoke()
        }
    }


    private fun tarSiteUrl(entry: SKTraceEntity): String {
        try {
            if (entry.siteType == null) {
                SkStorage.getString(BaseSiteSwitch.SITE_OBJ, null)?.let {
                    val siteVOF: SiteVOF = it.toBean()
                    BaseSiteSwitch.currentSite = siteVOF
                    if (siteVOF.type == 1) {
//                        YYLogUtils.e("9527 ---->  k1")
                        return BaseApiConfig.GB_PUB_TRACK_URL
                    } else if (BaseSiteSwitch.currentSite?.type == 2) {
//                        YYLogUtils.e("9527 ---->  k2")
                        return BaseApiConfig.US_PUB_TRACK_URL
                    }
                }
            } else {
                if (entry.siteType == 1) {
//                    YYLogUtils.e("9527 ---->  k3")
                    return BaseApiConfig.GB_PUB_TRACK_URL
                } else if (BaseSiteSwitch.currentSite?.type == 2) {
//                    YYLogUtils.e("9527 ---->  k4")
                    return BaseApiConfig.US_PUB_TRACK_URL
                }
            }
        } catch (e: Exception) {
            YYLogUtils.e("9527 ---->  严重错误------")
        }
//        YYLogUtils.e("9527 ---->  k5")
        return BaseApiClient.getCurrSvrCfgTrackerHost()
    }

    private fun getBaseSKTraceEntity(): SKTraceEntity {
        var entity = SKTraceEntity()
        entity.env = SpmDefaultConfig.env
        entity.clientVersion = clientVersion
        entity.clientBuild = buildNumber
        entity.osVersion = osVersion
        entity.networkType = networkType
        entity.model = mModel
        entity.brand = brand
        entity.language = language
        entity.tz = tz
        entity.deviceId = deviceId
//        entity.timeSinceLaunch
        entity.sessionId = sessionId
        return entity
    }


//    fun addTrackDataWithPriority(models: List<SKTraceEntity>, priority: SpmPriority) {
//    }

//    fun qryTrackDataByFlag(
//        rowFlag: Int,
//        env: Int,
//        page: Int,
//        pageSize: Int
//    ): List<SKTraceEntity> {
//        TODO("Not yet implemented")
//    }
//
//    fun qryTrackData(env: Int, page: Int, pageSize: Int): List<SKTraceEntity> {
//        TODO("Not yet implemented")
//    }
//
//    fun countRows(env: Int): Int {
//        return 1
//    }
//
//    fun deleteByEnv(env: Int): Int {
//        return 1
//    }
//
//    fun deleteTrackData(models: List<SKTraceEntity>): Boolean {
//        return false
//    }
//
//    fun signTrackData(models: List<SKTraceEntity>, success: Boolean): Boolean {
//        return false
//    }

    /**
     * 组装内容上报数据
     */
    fun trackPostMap(
        position: Int,
        post: PostF,
        traceId: String = ""
    ) = mapOf(
        "itemId" to post.id,
        "contentType" to (post.contentType ?: "1"),
        "index" to position.toString(),
        "traceId" to (traceId.ifEmpty { post.traceId ?: "" }),
    )

    fun trackPostMap(
        position: Int,
        post: PostD,
        traceId: String = ""
    ) = mapOf(
        "itemId" to post.id,
        "contentType" to (post.contentType ?: "1"),
        "index" to position.toString(),
        "traceId" to (traceId.ifEmpty { post.traceId ?: "" }),
    )

    /**
     * 组装商品上报数据
     */
    fun trackProductMap(
        position: Int,
        product: ProductF,
        traceId: String = ""
    ) = mutableMapOf(
        "index" to (position.toString()),
        "id" to (product.id ?: ""),
        "productId" to (product.productId ?: ""),
        "standardSpuIds" to (product.standardSpuIds ?: ""),
        "type" to (product.type.toString()),
        "merchantName" to (product.merchantWeb?.merchantName ?: ""),
    ).apply {
        if (traceId.isNullOrEmpty()) {
            if (!product.traceId.isNullOrEmpty()) {
                put("traceId", product.traceId!!)
            }
        } else {
            put("traceId", traceId)
        }
        if (product.affInfo != null && !product.affInfo!!.link.isNullOrEmpty()) {
            put(
                "affInfo",
//                URLEncoder.encode(
                product.affInfo!!.toJson(),
//                    "utf-8"
//                )
            )
        }
        if (product.disCountInfo != null && product.disCountInfo?.discountPercent.isNullOrEmpty()
                .not()
        ) {
            put("ribbon", "sales")
        }
    }

    fun trackProductMap(
        position: Int,
        product: ProductD,
        traceId: String = ""
    ) = mutableMapOf(
        "index" to (position.toString()),
        "id" to (product.id ?: ""),
        "productId" to (product.productId ?: ""),
        "standardSpuIds" to (product.standardSpuIds ?: ""),
        "type" to (product.type.toString()),
        "merchantName" to (product.merchantWeb?.merchantName ?: ""),
        "exps" to (product.exps ?: ""),
    ).apply {
        if (traceId.isNullOrEmpty()) {
            if (!product.traceId.isNullOrEmpty()) {
                put("traceId", product.traceId!!)
            }
        } else {
            put("traceId", traceId)
        }
        if (product.affInfo != null && !product.affInfo!!.link.isNullOrEmpty()) {
            put(
                "affInfo",
//                URLEncoder.encode(
                product.affInfo!!.toJson()
//                , "utf-8"
//                )
            )
        }

        if (product.disCountInfo != null && product.disCountInfo?.discountPercent.isNullOrEmpty()
                .not()
        ) {
            put("ribbon", "sales")
        }
    }

    fun trackProductOfferMap(
        position: Int,
        product: ProductOffer,
    ) = mutableMapOf(
        "index" to (position.toString()),
        "id" to (product.id ?: ""),
        "productId" to (product.productId ?: ""),
        "standardSpuIds" to (product.standardSpuIds ?: ""),
        "type" to (product.type.toString()),
        "merchantName" to (product.merchantWeb?.merchantWebVOF?.merchantName ?: ""),
    ).apply {
        if (product.affInfo != null && !product.affInfo!!.link.isNullOrEmpty()) {
            put(
                "affInfo",
//                URLEncoder.encode(
                product.affInfo!!.toJson(),
//                "utf-8"
//                )
            )
        }
    }

    fun trackProductOfferMap(
        position: Int,
        product: BrotherOfferF,
    ) = mutableMapOf(
        "index" to (position.toString()),
        "id" to (product.id ?: ""),
        "productId" to (product.productId ?: ""),
        "standardSpuIds" to (product.standardSpuIds ?: ""),
        "type" to (product.type.toString()),
        "merchantName" to (product.merchantWeb?.merchantName ?: ""),
    ).apply {
        if (!product.traceId.isNullOrEmpty()) {
            put("traceId", product.traceId!!)
        }
        if (product.affInfo != null && !product.affInfo!!.link.isNullOrEmpty()) {
            put(
                "affInfo",
//                URLEncoder.encode(
                product.affInfo!!.toJson(),
//                "utf-8"
//                )
            )
        }
    }

}